package namespaces

import (
	"errors"
	"fmt"
	"sync"

	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/asteroid/cluster"
	"gddgame.cc/galaxy/binocle"
	"gddgame.cc/galaxy/common/bootstrap"
	"gddgame.cc/galaxy/common/feature/orbit/chess_protocol"
	"gddgame.cc/galaxy/common/namespaces/cooperate"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/common/service/pathfinding"
	"gddgame.cc/galaxy/core/sdk"
	"gddgame.cc/galaxy/satellite/formula/nebula"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/serialize"
)

// Map Namespace
const (
	CooperateRegisterAccount nebula.NSE = iota
	CooperateApplyAccount

	CooperateSwitchMap

	CooperateOperateData
	CooperateGetData
	CooperateListData
	CooperatePartData

	CooperateRegister
	CooperateUnRegister

	CooperateAddSchedule
	CooperateBindEvent

	CooperateGetTasks
	CooperateFinishTask
	CooperateAddTask

	CooperatePathFinding
	CooperateDataPathFinding
	CooperateQueryPathFinding

	CooperateQueryMap
	CooperateQueryManageMap
	CooperateRefreshAuth

	CooperateApplyManager
	CooperateOnReleaseManager

	CooperateOnNoticeNode = 120
	CooperateOnAccount    = 121

	CooperateOnNoticeCreate = 126
	CooperateOnNoticeUpdate = 127
	CooperateOnNoticeDelete = 128

	CooperateOnManagerCreate   = 129
	CooperateOnManagerUpdate   = 130
	CooperateOnManagerDelete   = 131
	CooperateOnManagerTransfer = 132

	CooperateInlineCreate = 200
	CooperateInlineNotice = 201
)

type UserManager interface {
	GetAccountId(userId int) (int, int)
	SaveAccount(userId int, id int, identity int) error
	JoinMap(userId int, mapNoId string, ai bool) (need bool, have bool)
}

type AiManager interface {
	ApplyAi() (string, int, int)
	GenerateAi(openId string, id int, identity int) (int, error)
	ReleaseAi(userId int)
	ApplyManager(id string, node string, number int) []string
	OnReleaseManager(id string, node string, mapNoIds []string)
}

type CooperateManager interface {
	Depends() error
	Clear() error
	StartMap(mapNoId string, node string)
	StopMap(mapNoId string, fn func(), node string)
	ParseMap(data []byte) *cooperate.MapData
	Service() *cooperate.LogicWrap
	ReleaseManager(node string, id string, mapNoId string)
}

type CooperateDelegate interface {
	cooperate.TypeContentProvider
	cooperate.MapNodeDelegate
	GetTypeDefinedManager() cooperate.TypeDefinedManager
	GetTypeDefined(mapNoId string) (cooperate.TypeDefined, *cooperate.MapInfo, int)
	GetAccessTokenPolicy(namespace string, token string) map[string]interface{}
	GetUserManager() UserManager
	GetAiManager() AiManager
	PreLoadMap(node string)
	StartSuccess(mapNoId string)
	StopSuccess(mapNoId string)
	DefaultMap() string
}

type cooperateSingleRegister struct {
	Store  sync.Map
	Mutex  sync.Mutex
	Change bool
	List   []*nebula.Socket
}

type cooperateRegisterManager struct {
	//MapNoId string
	mutex sync.RWMutex
	idMap map[string]*cooperateSingleRegister
}

//
func newRegisterManager() *cooperateRegisterManager {
	m := &cooperateRegisterManager{
		//MapNoId: mapNoId,
		mutex: sync.RWMutex{},
		idMap: map[string]*cooperateSingleRegister{},
	}
	return m
}

func (m *cooperateRegisterManager) Register(ids []interface{}, socket *nebula.Socket) {
	for _, id := range ids {
		var v *cooperateSingleRegister
		idString := utils.ToString(id)
		m.mutex.Lock()
		v, ok := m.idMap[idString]
		if !ok {
			v = &cooperateSingleRegister{
				Store:  sync.Map{},
				Mutex:  sync.Mutex{},
				Change: false,
				List:   []*nebula.Socket{socket},
			}
			m.idMap[idString] = v
		}
		m.mutex.Unlock()
		v.Store.Store(socket.ID(), socket)
	}
}

func (m *cooperateRegisterManager) UnRegister(ids []interface{}, socket *nebula.Socket) {
	for _, id := range ids {
		var v *cooperateSingleRegister
		idString := utils.ToString(id)
		m.mutex.RLock()
		v, ok := m.idMap[idString]
		m.mutex.RUnlock()
		if !ok {
			continue
		}
		v.Mutex.Lock()
		v.Store.Delete(socket.ID())
		v.Change = true
		v.Mutex.Unlock()
	}
}

func (m *cooperateRegisterManager) UnRegisterAll(socket *nebula.Socket) {
	id := socket.ID()
	m.mutex.RLock()
	for _, v := range m.idMap {
		v.Mutex.Lock()
		v.Store.Delete(id)
		v.Change = true
		v.Mutex.Unlock()
	}
	m.mutex.RUnlock()
}

func (m *cooperateRegisterManager) GetRegister(id interface{}) []*nebula.Socket {
	idString := utils.ToString(id)
	m.mutex.RLock()
	v, ok := m.idMap[idString]
	m.mutex.RUnlock()
	if !ok {
		return nil
	}
	if !v.Change {
		return v.List
	}
	v.Mutex.Lock()
	v.List = v.List[0:0]
	v.Store.Range(func(key, value interface{}) bool {
		v.List = append(v.List, value.(*nebula.Socket))
		return true
	})
	v.Mutex.Unlock()
	return nil
}

type cooperateInstance struct {
	MapNoId string
	Waiting bool
	Running bool
	Path    *pathfinding.Rule

	RegisterNodeMap *cooperateRegisterManager

	*cluster.Client
	*cooperate.MapInstance
}

func (instance *cooperateInstance) GetMapInstance() *cooperate.MapInstance {
	return instance.MapInstance
}

func (instance *cooperateInstance) GetClient() *cluster.Client {
	return instance.Client
}

type cooperateService struct {
	builder composer.Builder
	binocle.App

	*cooperate.LogicWrap

	MasterMap sync.Map
	PF        *pathfinding.Service

	CooperateDelegate
}

func (service *cooperateService) Depends() error {
	return nil
}

func (service *cooperateService) ID() string {
	return "cooperate"
}

func (service *cooperateService) ParseMap(data []byte) *cooperate.MapData {
	d := &cooperate.MapData{}
	if _, err := d.UnmarshalMsg(data); err != nil {
		fmt.Println("parseMap", err)
	}
	return d
}

func (service *cooperateService) IsMaster(mapNoId string) bool {
	v, ok := service.MasterMap.Load(mapNoId)
	if !ok {
		return false
	}
	return v.(bool)
}

func (service *cooperateService) OnStart(mapNoId string) {
	instance := service.GetMapInstance(mapNoId).(*cooperateInstance)
	if instance.Running {
		return
	}
	if instance.Waiting {
		return
	}
	instance.Waiting = true

	go func() {
		service.InitInstance(instance)
	}()
}

func (service *cooperateService) OnStop(mapNoId string) {
	instance := service.GetMapInstance(mapNoId).(*cooperateInstance)
	if service.IsMaster(mapNoId) {
		// 删除地图数据
		instance.Path.Stop()
		// 删除同步数据
		service.OnStopMap(instance.MapInstance)
		service.CooperateDelegate.StopSuccess(mapNoId)
	}
	instance.Running = false
}

func (service *cooperateService) OnNotice(socket *nebula.Socket, notice *cooperate.Notice) {
	// 判断是否是ai执行
	var accountId int
	_ = socket.Get("account_id", accountId)
	// 传递的数据格式
	if accountId == notice.AccountId {
		r, _ := socket.Trigger(CooperateInlineNotice, []interface{}{notice.Event, notice.Content})
		if r != nil {
			r.Finish()
		}
	}
}

func (service *cooperateService) OnUpdateNode(mapNoId string, item *cooperate.NoticeContent, deleteStatus bool, d cooperate.PropsInstance) {
	instance := service.GetMapInstance(mapNoId).(*cooperateInstance)
	if service.IsMaster(mapNoId) {
		if deleteStatus {
			instance.Path.UpdateNode(utils.ToBytes(item.Data.Id), 0, 0)
		} else {
			node := d.(cooperate.BaseItem)
			instance.Path.UpdateNode(utils.ToBytes(item.Data.Id), node.GetIdentity(), node.GetType())
		}
	}
	if d != nil {
		sockets := instance.RegisterNodeMap.GetRegister(item.Data.Id)
		if sockets != nil && len(sockets) > 0 {
			for _, socket := range sockets {
				if socket != nil {
					_ = socket.Emit(CooperateOnNoticeNode, d)
				}
			}
		}
	}
}

func (service *cooperateService) OnNoticeAccount(oldSocket *nebula.Socket, newSocket *nebula.Socket, item *cooperate.NoticeContent, deleteStatus bool, d cooperate.PropsInstance, content *chess_protocol.UpdatePublicData) {
	// create不会像同步一样，在create的时候发送事件
	// 自己拥有的对象在客户端是长存的，ignore字段不生效，由客户端自行
	// 只会在update中下发message
	//if item.OldAccountId > 0 || item.NewAccountId > 0 {
	//	fmt.Println("notice", item.OldAccountId, item.NewAccountId, d.Data())
	//}
	if item.OldAccountId == 0 {
		// 新数据
		if newSocket != nil {
			//fmt.Println("notice create", item.Data)
			r, _ := newSocket.Trigger(CooperateInlineCreate, []interface{}{item.Data.DataType, item.Data.Id})
			if r != nil {
				r.Finish()
			}
			_ = newSocket.Emit(CooperateOnNoticeCreate, item.NewAccountId, item.Data.DataType, item.Data.Id, d)
		}
	} else if item.NewAccountId == 0 {
		if oldSocket != nil {
			//fmt.Println("notice delete", oldSocket, item, content)
			_ = oldSocket.Emit(CooperateOnNoticeDelete, item.OldAccountId, item.Data.DataType, item.Data.Id, content)
		}
	} else {
		if item.OldAccountId == item.NewAccountId {
			if oldSocket != nil {
				//fmt.Println("notice update", item.Data)
				_ = oldSocket.Emit(CooperateOnNoticeUpdate, item.OldAccountId, item.Data.DataType, item.Data.Id, content)
			}
		} else {
			if oldSocket != nil {
				//fmt.Println("notice transfer", oldSocket, item, content)
				_ = oldSocket.Emit(CooperateOnNoticeDelete, item.OldAccountId, item.Data.DataType, item.Data.Id, content)
			}
			if newSocket != nil {
				//fmt.Println("notice create", item.Id)
				_ = newSocket.Emit(CooperateOnNoticeCreate, item.NewAccountId, d)
			}
		}
	}
}

func (service *cooperateService) OnNoticeManager(socket *nebula.Socket, mapNoId string, item *cooperate.NoticeContent, deleteStatus bool, d cooperate.PropsInstance, content *chess_protocol.UpdatePublicData) {
	// 如果地图变更，要走移除manager逻辑
	manager, oldManager := d.Manager(true)
	if manager != nil || oldManager != nil {
		if deleteStatus {
			//fmt.Println("manager delete", oldManager, manager, item)
			_ = socket.Emit(CooperateOnManagerDelete, mapNoId, oldManager.DataType, oldManager.Id, item.Data.DataType, item.Data.Id)
		} else if oldManager == nil {
			//fmt.Println("manager create", item.Data, oldManager, manager)
			if manager != nil {
				_ = socket.Emit(CooperateOnManagerCreate, mapNoId, manager.DataType, manager.Id, item.Data.DataType, item.Data.Id, d)
			}
		} else if manager == nil {
			_ = socket.Emit(CooperateOnManagerDelete, mapNoId, oldManager.DataType, oldManager.Id, item.Data.DataType, item.Data.Id, content)
		} else if !oldManager.Equal(manager) {
			_ = socket.Emit(CooperateOnManagerDelete, mapNoId, oldManager.DataType, oldManager.Id, item.Data.DataType, item.Data.Id, content)
			_ = socket.Emit(CooperateOnManagerCreate, mapNoId, manager.DataType, manager.Id, item.Data.DataType, item.Data.Id, d)
		} else {
			_ = socket.Emit(CooperateOnManagerUpdate, mapNoId, manager.DataType, manager.Id, item.Data.DataType, item.Data.Id, content)
		}
	}
}

func (service *cooperateService) OnReleaseManager(socket *nebula.Socket, mapNoId string) {
	_ = socket.Emit(CooperateOnReleaseManager, mapNoId)
	fmt.Println("on release manager", mapNoId)
	service.CooperateDelegate.GetAiManager().OnReleaseManager(socket.ID(), service.Node(), []string{mapNoId})
}

func (service *cooperateService) OnLoadMap(mapInstance *cooperate.MapInstance) {
	mapNoId := mapInstance.MapNoId
	path := pathfinding.NewRule(service, service.PF, mapNoId, 0)
	td, info, version := service.CooperateDelegate.GetTypeDefined(mapNoId)
	//fmt.Println("start map", mapInstance.MapNoId, td, info, version)
	service.MapManager.InitMap(mapInstance, mapNoId, td, info, version)
	mapInstance.OnPathInf = path
	service.ToMap(mapInstance)
	path.BindBlock(mapInstance.MapData.Block)
}

func (service *cooperateService) OnReloadMap(mapInstance *cooperate.MapInstance) {
	mapNoId := mapInstance.MapNoId
	path := mapInstance.OnPathInf.(*pathfinding.Rule)
	td, info, version := service.CooperateDelegate.GetTypeDefined(mapNoId)
	//fmt.Println("start map", instance.MapNoId, version)
	service.MapManager.InitMap(mapInstance, mapNoId, td, info, version)
	service.ToMap(mapInstance)
	path.BindBlock(mapInstance.MapData.Block)
}

func (service *cooperateService) Service() *cooperate.LogicWrap {
	return service.LogicWrap
}

func (service *cooperateService) Init(node cluster.Node) {
	node.SetConfig(cluster.ThreadSafe, false)
}

func (service *cooperateService) InitInstance(instance *cooperateInstance) bool {
	// 这里要注意初始化的顺序
	mapInstance := instance.MapInstance
	fmt.Println("start map", instance.MapNoId, mapInstance.MapData.Block)

	instance.Path = mapInstance.OnPathInf.(*pathfinding.Rule)
	_, ok := service.MasterMap.Load(instance.MapNoId)
	items := mapInstance.LoadMapData(ok)
	if ok {
		mapInstance.Master = true
		fmt.Println("load data start")
		// 发送同步数据
		mapData := mapInstance.MapData
		start := pathfinding.Vector2{X: mapData.CenterVector2.X - mapData.SizeVector2.X, Y: mapData.CenterVector2.Y - mapData.SizeVector2.Y}
		// 加载地图数据
		sn := make([]pathfinding.DefineNode, 0, 100)
		sm := make(map[int16]int, 100)
		for _, v := range items {
			itemByte := v.GetItem()
			po := pathfinding.DecodeVector2(v.GetPosition())
			sIndex := start.Index(mapData.SizeVector2, po)
			var n *pathfinding.DefineNodeContent
			if d, ok := sm[sIndex]; ok {
				n = sn[d].Node
			} else {
				sm[sIndex] = len(sn)
				n = &pathfinding.DefineNodeContent{}
				sn = append(sn, pathfinding.DefineNode{
					Node:     n,
					Position: *po,
				})
			}
			if v.IsFixed() {
				fixed := &pathfinding.Fixed{
					Item:     itemByte,
					Identity: v.GetIdentity(),
					Type:     v.GetType(),
					View:     v.GetView(),
				}
				n.Fixed = fixed
				if v.GetView() > 0 {
					n.HasView = true
				}
				pp := pathfinding.DecodeVector2Slice(v.GetPositions())
				for _, ppp := range pp {
					sIndex := start.Index(mapData.SizeVector2, &ppp)
					var n *pathfinding.DefineNodeContent
					if d, ok := sm[sIndex]; ok {
						n = sn[d].Node
					} else {
						sm[sIndex] = len(sn)
						n = &pathfinding.DefineNodeContent{}
						sn = append(sn, pathfinding.DefineNode{
							Position: ppp,
							Node:     n,
						})
					}
					n.Fixed = fixed
					if v.GetView() > 0 {
						n.HasView = true
					}
				}
			} else if v.IsSeat() {
				seat := pathfinding.Seat{
					Item:      itemByte,
					Identity:  v.GetIdentity(),
					EndTime:   0,
					StartTime: service.MapManager.CurrentTime(),
					Extend:    v.GetExtend(),
					View:      v.GetView(),
				}
				//fmt.Println("seat", seat, v.GetPosition(), v.GetPositions())
				n.Seat = &seat
				if v.GetView() > 0 {
					n.HasView = true
				}
			} else {
				n.Identity = v.GetIdentity()
				n.Type = v.GetType()
			}
			relationLinks := v.GetRelationLink()
			if relationLinks != nil {
				for relation, positions := range relationLinks {
					pp := pathfinding.DecodeVector2Slice(positions)
					for _, ppp := range pp {
						sIndex := start.Index(mapData.SizeVector2, &ppp)
						var n *pathfinding.DefineNodeContent
						if d, ok := sm[sIndex]; ok {
							n = sn[d].Node
						} else {
							sm[sIndex] = len(sn)
							n = &pathfinding.DefineNodeContent{}
							sn = append(sn, pathfinding.DefineNode{
								Position: ppp,
								Node:     n,
							})
						}
						if n.LinkMap == nil {
							n.LinkMap = []*pathfinding.RelationLinkManager{}
						}
						var manager *pathfinding.RelationLinkManager
						if len(n.LinkMap) <= int(relation) {
							manager = &pathfinding.RelationLinkManager{
								Relation: relation,
								Items:    [][]byte{},
							}
							n.LinkMap = append(n.LinkMap, make([]*pathfinding.RelationLinkManager, int(relation)-len(n.LinkMap)+1)...)
							n.LinkMap[relation] = manager
						} else {
							manager = n.LinkMap[relation]
						}

						manager.Items = append(manager.Items, itemByte)
					}
				}
			}

		}
		for _, v := range mapData.DataNodes {
			p := pathfinding.DecodeVector2(v.Position)
			i := start.Index(mapData.SizeVector2, p)
			t := v.Type

			if d, ok := sm[i]; ok {
				sn[d].Position = *p
				if sn[d].Node.Type == 0 {
					sn[d].Node.Type = t
				}
			} else {
				sn = append(sn, pathfinding.DefineNode{
					Position: *p,
					Node:     &pathfinding.DefineNodeContent{Type: t, Identity: 0},
				})
			}
		}

		data := &pathfinding.RegisterData{
			Size:         *mapData.SizeVector2,
			Center:       *mapData.CenterVector2,
			RangeGap:     15,
			Mode:         pathfinding.MapMode(mapData.Mode),
			Nodes:        sn,
			Boundary:     pathfinding.DecodeVector2Slice(mapData.Boundary), //pathfinding.Vector2Slice{}
			NodeCostList: mapInstance.MapInfo.NodeCostList,
		}

		slot := serialize.GetSlot()
		if err := slot.Set(data); err != nil {
			fmt.Println("register", err)
		}
		//fmt.Println("load data finish")
		go func() {
			instance.Path.Init(slot, func() {
				fmt.Println("map  path inited")
				slot.Release()
				service.Dispatch(instance.MapInstance)
				service.CooperateDelegate.StartSuccess(instance.MapNoId)
				instance.Running = true
				instance.Waiting = false
			})
		}()
	} else {
		go func() {
			service.Dispatch(instance.MapInstance)
			instance.Running = true
			instance.Waiting = false
		}()
	}

	return true
}

func (service *cooperateService) InitClient(client *cluster.Client) {
	mapNoId := client.ID()
	instance := &cooperateInstance{
		Client:  client,
		MapNoId: mapNoId,
	}
	mapInstance := service.MapManager.ReloadMap(instance.MapNoId)
	instance.MapInstance = mapInstance
	instance.RegisterNodeMap = newRegisterManager()

	client.SetInstance(instance)
	service.Share.InitClient(instance, client)
}
func (service *cooperateService) CloseInstance(node cluster.Node) {
}
func (service *cooperateService) CloseClient(client *cluster.Client) {
	instance := client.Instance().(*cooperateInstance)
	service.OnStopMap(instance.MapInstance)
	service.CooperateDelegate.StopSuccess(instance.MapNoId)
}

func (service *cooperateService) Master(node cluster.Node) {
	service.MasterMap.Store(node.Token(), true)
}

func CooperateHandler(builder composer.Builder, namespace nebula.Namespace, client *sdk.AppClient, delegate CooperateDelegate) CooperateManager {
	// 注册Cooperate服务
	var agent binocle.App
	builder.Factory("agent", &agent)
	var boot *bootstrap.Boot
	builder.Factory("boot", &boot)

	cooperateManager := &cooperateService{builder: builder, App: agent}
	_ = builder.BindInstance("cooperate", cooperateManager)

	// 寻路服务创建
	pfService := pathfinding.NewService()
	hexRule := pathfinding.NewHexRule()
	agent.Cluster().RegisterBalance(pfService)

	// 绑定系统通道
	cooperateManager.CooperateDelegate = delegate
	cooperateManager.MasterMap = sync.Map{}
	cooperateManager.PF = pfService

	dm := cooperate.GetData()
	mapManager := cooperate.NewMapManager(builder, dm, hexRule)
	mapManager.TypeContentProvider = delegate
	mapManager.MapLoadDelegate = cooperateManager

	td := delegate.GetTypeDefinedManager()
	td.Register(dm)

	if err := dm.Init(); err != nil {
		builder.Error(err)
	}
	logic, err := cooperate.NewLogicExecute(agent, boot.Redis())
	if err != nil {
		builder.Error(err)
	}
	logic.SetMapManager(mapManager)
	logic.BindCancel(builder.Ctx())
	logic.BindType(td)
	logic.BindService(cooperateManager, cooperateManager)
	logic.StartQueue()

	cooperateManager.LogicWrap = logic

	agent.Cluster().RegisterBalance(cooperateManager)
	orbit := false
	agent.MountNode(func(node cluster.Node) {
		node.On("preLoadMap", func(message asteroid.Message) {
			delegate.PreLoadMap(node.CurrentNode())
		})
	})
	agent.AddMasterListen(func(node cluster.Node) {
		if orbit {
			agent.Client().Emit().Node(node.CurrentNode()).Send("preLoadMap")
		}
	})
	agent.OnTargetConnect("orbit", func(target string, node string, number int) {
		if agent.IsMaster() {
			if number == 1 {
				agent.Client().Emit().Send("preLoadMap")
			}
		}
		orbit = true
	})

	userManager := delegate.GetUserManager()
	aiManager := delegate.GetAiManager()
	_ = namespace.Connect(func(socket *nebula.Socket, next nebula.Next) {
		server := false
		_, ok := socket.Query("server")
		if ok {
			server = true

		}
		mapNoId := ""
		openId := ""
		var instance *cooperateInstance
		userId := 0
		taskQueue := make([]string, 0, 10)

		//taskMutex := sync.Mutex{}
		aiUserMap := map[int]int{}
		aiIdentityMap := map[int]int{}
		aiManagerList := []string{}

		accountId := 0
		identity := 0

		_ = socket.On(CooperateRegisterAccount, func(identityNumber int) interface{} {
			identity = cooperateManager.GetRealIdentity(identityNumber)
			accountId = cooperateManager.MakeAccount(userId, openId, identity)
			fmt.Println("register", userId, identity, accountId)
			if err := userManager.SaveAccount(userId, accountId, identity); err != nil {
				fmt.Println("register fail", err)
				return nil
			}

			_ = socket.Set("account_id", accountId)
			_ = socket.Set("identity", identity)
			cooperateManager.RegisterAccount(accountId, socket)

			account := cooperateManager.GetData(cooperateManager.DefaultMap(), cooperate.AccountType, accountId)
			fmt.Println("account", account)
			return account.(interface{})
		})
		_ = socket.On(CooperateApplyAccount, func() int {
			// 申请ai账号
			aiOpenId, aiUserId, aiAccountId := aiManager.ApplyAi()
			fmt.Println("apply account", aiOpenId, aiUserId, aiAccountId)
			var idid int
			if aiAccountId > 0 {
				idid = cooperateManager.GetRandomIdentity()
				cooperateManager.ExistAccount(aiAccountId, aiOpenId, idid)
			}
			if aiAccountId == 0 {
				idid = cooperateManager.GetRandomIdentity()
				accountId := cooperateManager.MakeAccount(aiUserId, aiOpenId, idid)
				aiAccountId = accountId
				if userId, err := aiManager.GenerateAi(aiOpenId, accountId, idid); err != nil {
					fmt.Println("generate", err)
					return 0
				} else {
					aiUserId = userId
				}
			}
			cooperateManager.RegisterAccount(aiAccountId, socket)
			aiUserMap[aiAccountId] = aiUserId
			aiIdentityMap[aiAccountId] = idid
			fmt.Println("ai", aiAccountId)
			return aiAccountId
		})
		_ = socket.On(CooperateSwitchMap, func(id string) (byte, byte, byte) {
			socket.Debugf("[ Cooperate ] switch: %s", id)
			l := cooperateManager.GetMapInstance(id)
			if l == nil {
				fmt.Println(errors.New("Cooperate query error: mapId is error"))
				return 0, 0, 0
			}
			instance = l.(*cooperateInstance)
			if instance == nil {
				fmt.Println(errors.New("Cooperate query error: mapId not running"))
				return 1, 0, 0
			}
			if instance.Waiting == true {
				fmt.Println(errors.New("Cooperate query error: mapId waiting"))
				return 2, 0, 0
			}

			mapNoId = id
			_, have := userManager.JoinMap(userId, id, false)
			if !have {
				// 第一次进入
			}

			// 保存地图
			if err := socket.Set("map_no_id", mapNoId); err != nil {
				fmt.Println("socket", err)
			}

			instance.RegisterNodeMap.UnRegisterAll(socket)
			mapNoId = id
			cooperateManager.UpdateAccount(accountId, map[string]interface{}{
				cooperate.MapNoId: mapNoId,
			})
			for _, aiUserId := range aiUserMap {
				need, have := userManager.JoinMap(aiUserId, mapNoId, true)
				if !need {
					break
				}
				if !have {
					// 通知客户端
				}
			}
			// 返回地图block
			block := instance.Block()
			//fmt.Println("block", block)
			return 3, utils.ToByte(block.X), utils.ToByte(block.Y)
		})
		_ = socket.On(CooperateOperateData, func(m string, from []byte, target []byte, checkList []byte, operateList []byte, time int64, message []byte) {
			if m == "" {
				m = mapNoId
			}
			cooperateManager.Operate(m, from, target, checkList, operateList, time, message)
		})
		_ = socket.On(CooperateGetData, func(m string, t byte, id interface{}) interface{} {
			if m == "" {
				m = mapNoId
			}
			dd := cooperateManager.GetData(m, structure.PublicDataType(t), id)
			//debug.PrintStack()
			//fmt.Println(m, t, id, dd)
			if dd == nil {
				return nil
			}
			return dd.(interface{})
		})
		_ = socket.On(CooperatePartData, func(m string, t byte, id interface{}, props []string, fields []string) interface{} {
			if m == "" {
				m = mapNoId
			}
			dd := cooperateManager.GetData(m, structure.PublicDataType(t), id)
			//debug.PrintStack()
			//fmt.Println(m, t, id, dd)
			if dd == nil {
				return nil
			}
			d := make([]interface{}, len(props)+len(fields))
			for i, prop := range props {
				//fmt.Println(part, dd.Receive(cooperate.PropType(part)))
				d[i] = dd.Receive(cooperate.PropType(prop))
			}
			for i, field := range fields {
				d[i+len(props)] = dd.GetProp(field)
			}
			return d
		})
		_ = socket.On(CooperateListData, func(m string, t byte, ids []interface{}) interface{} {
			if m == "" {
				m = mapNoId
			}
			l := cooperateManager.ListData(m, structure.PublicDataType(t), ids)
			return l
		})
		_ = socket.On(CooperateRegister, func(ids []interface{}) {
			instance.RegisterNodeMap.Register(ids, socket)
		})
		_ = socket.On(CooperateUnRegister, func(ids []interface{}) {
			instance.RegisterNodeMap.UnRegister(ids, socket)
		})
		_ = socket.On(CooperateAddSchedule, func(m string, from []byte, target []byte, key string, schedule byte, time int64, content []byte, params []interface{}, delay int) {
			if m == "" {
				m = mapNoId
			}
			cooperateManager.AddSchedule(m, from, target, key, schedule, time, content, params, delay)
		})
		//_ = socket.On(CooperateBindEvent, func(m string, from []byte, target []byte, event byte, mode byte, content []byte) {
		//	if m == "" {
		//		m = mapNoId
		//	}
		//	cooperateManager.BindEvent(m, from, target, event, mode, content)
		//})
		_ = socket.On(CooperateGetTasks, func(indexs []int) interface{} {
			//fmt.Println("task request", indexs, taskQueue)
			//start := time.Now()
			number := 0
			for _, index := range indexs {
				if len(taskQueue) > index && taskQueue[index] != "" {
					continue
				}
				number++
			}
			ti := cooperateManager.GetTasks(number)
			if ti == nil {
				//fmt.Println("task miss")
				return []interface{}{}
			}
			number = len(ti)
			//taskMutex.Lock()
			for _, index := range indexs {
				if number == 0 {
					break
				}
				if len(taskQueue) <= index {
					taskQueue = append(taskQueue, make([]string, index-len(taskQueue)+1)...)
				} else if taskQueue[index] != "" {
					continue
				}
				number--
				taskQueue[index] = ti[number].Sid
				//result[i] = ti[number]
			}
			//taskMutex.Unlock()
			//fmt.Println("task request", indexs, taskQueue)
			//fmt.Println("task:", start, time.Now().Sub(start))
			return ti
		})
		_ = socket.On(CooperateFinishTask, func(index int, callback []byte, success bool) {
			if len(taskQueue) <= index {
				return
			}
			//fmt.Println("finish", index, success)
			taskKey := taskQueue[index]
			if taskKey != "" {
				if success {
					//cb := &cooperate.TaskCallback{}
					//_, _ = cb.UnmarshalMsg(callback)
					//// 发送任务完成回掉
					//agent.Client().Emit().Node(cb.Node).Data(cb.Uuid).Send("task")
					cooperateManager.FinishTask(taskKey)
				} else {
					cooperateManager.RestoreTask(taskKey)
				}
				taskQueue[index] = ""
			}
		})

		_ = socket.On(CooperateAddTask, func(m string, from []byte, task byte, time int64, content []byte, params []interface{}, uuid string) {
			if m == "" {
				m = mapNoId
			}
			if uuid != "" {
				cooperateManager.AddTask(m, from, task, time, content, params, &cooperate.TaskCallback{Node: agent.Node(), Uuid: uuid})
			} else {
				cooperateManager.AddTask(m, from, task, time, content, params, nil)
			}
		})

		//_ = socket.On(CooperatePathFinding, func(m string, event byte, params []interface{}) interface{} {
		//	//fmt.Println("cooperate path", event, params)
		//	var i *cooperateInstance
		//	if m == mapNoId || m == "" {
		//		i = instance
		//	} else {
		//		l, ok := cooperateManager.InstanceMap.Load(m)
		//		if !ok {
		//			return errors.New("Cooperate query error: mapId is error")
		//		}
		//		i = l.(*cooperateInstance)
		//	}
		//
		//	return i.Path.ServiceExecute(event, params)
		//})
		//_ = socket.On(CooperateDataPathFinding, func(m string, t byte, id interface{}, event byte, params []interface{}) interface{} {
		//	//fmt.Println("cooperate path", event, params)
		//	d := &structure.BaseData{
		//		DataType: structure.PublicDataType(t),
		//		Id:       id,
		//	}
		//	params = append(params, d.GetItem())
		//	var i *cooperateInstance
		//	if m == mapNoId || m == "" {
		//		i = instance
		//	} else {
		//		l, ok := cooperateManager.InstanceMap.Load(m)
		//		if !ok {
		//			return errors.New("Cooperate query error: mapId is error")
		//		}
		//		i = l.(*cooperateInstance)
		//	}
		//	return i.Path.ServiceExecute(event, params)
		//})
		//_ = socket.On(CooperateQueryPathFinding, func(m string, position []byte, event byte, params []interface{}) interface{} {
		//	var i *cooperateInstance
		//	if m == mapNoId || m == "" {
		//		i = instance
		//	} else {
		//		l, ok := cooperateManager.InstanceMap.Load(m)
		//		if !ok {
		//			return errors.New("Cooperate query error: mapId is error")
		//		}
		//		i = l.(*cooperateInstance)
		//	}
		//	value := i.Path.ServiceExecute(event, params)
		//	switch v := value.(type) {
		//	case []byte:
		//		return structure.NewBaseDataByte(v)
		//	default:
		//		return nil
		//	}
		//})
		_ = socket.On(CooperateQueryMap, func(m string, aid int, event byte, params []interface{}) interface{} {
			var i *cooperateInstance
			var idid int
			var ok bool
			l := cooperateManager.GetMapInstance(m)
			if l == nil {
				return errors.New("Cooperate query error: mapId is error")
			}
			i = l.(*cooperateInstance)
			if aid > 0 && accountId != aid {
				idid, ok = aiIdentityMap[aid]
				if !ok {
					return errors.New("Cooperate query error: accountId is error:" + utils.ToString(aid) + ":" + utils.ToString(accountId))
				}
			} else if aid > 0 {
				idid = identity
			} else {
				idid = 0
			}
			r := i.MapInstance.OnQuery(aid, idid, event, params)
			//fmt.Println("result", r)
			return r
		})
		_ = socket.On(CooperateQueryManageMap, func(m string, idid int, event byte, params []interface{}) interface{} {
			var i *cooperateInstance
			//if !server {
			//	return errors.New("Cooperate query error: auth error")
			//}
			// todo 获取代理接口执行
			l := cooperateManager.GetMapInstance(m)
			if l == nil {
				return errors.New("Cooperate query error: mapId is error")
			}
			i = l.(*cooperateInstance)
			r := i.MapInstance.OnQuery(0, idid, event, params)
			//fmt.Println("result", r)
			return r
		})
		_ = socket.On(CooperateRefreshAuth, func() interface{} {
			auth, err := client.GenerateAccessToken(openId, cooperateManager.CooperateDelegate.GetAccessTokenPolicy("cooperate", ""), 30)
			if err != nil {
				return err
			}
			return auth
		})
		_ = socket.On(CooperateApplyManager, func(number int) interface{} {
			// 客户端定时执行
			list := aiManager.ApplyManager(socket.ID(), agent.Node(), number)
			for _, mapNoId := range list {
				aiManagerList = append(aiManagerList, mapNoId)
				cooperateManager.RegisterManager(mapNoId, socket)
			}
			return list
		})
		_ = socket.Disconnected(func(reason string) {
			// 未完成任务，重新分配
			for _, taskKey := range taskQueue {
				if taskKey == "" {
					continue
				}
				cooperateManager.RestoreTask(taskKey)
			}
			if len(aiUserMap) > 0 {
				for aiAccountId, userId := range aiUserMap {
					aiManager.ReleaseAi(userId)
					cooperateManager.UnRegisterAccount(aiAccountId)
				}
			}
			if len(aiManagerList) > 0 {
				for _, mapNoId := range aiManagerList {
					cooperateManager.UnRegisterManager(mapNoId)
				}

				aiManager.OnReleaseManager(socket.ID(), agent.Node(), aiManagerList)
			}
			if accountId > 0 {
				cooperateManager.UnRegisterAccount(accountId)
			}
			if instance != nil {
				instance.RegisterNodeMap.UnRegisterAll(socket)
			}
		})

		// 客户端模式，绑定账号
		if !server {
			if err := socket.Get("open_id", &openId); err != nil {
				_ = next(errors.New("Auth error"))
				return
			}
			if err := socket.Get("user_id", &userId); err != nil {
				_ = next(errors.New("Auth error"))
				return
			}
			accountId, identity = userManager.GetAccountId(userId)
			auth, err := client.GenerateAccessToken(openId, cooperateManager.CooperateDelegate.GetAccessTokenPolicy("cooperate", ""), 30)
			_ = next(err)
			fmt.Println("login", accountId, identity, err)
			if err != nil {
				return
			} else {
				if accountId > 0 {
					_ = socket.Set("account_id", accountId)
					_ = socket.Set("identity", identity)

					cooperateManager.RegisterAccount(accountId, socket)
					cooperateManager.ExistAccount(accountId, openId, identity)
					account := cooperateManager.TmpData(cooperate.AccountType, accountId)
					fmt.Println("account", account)
					_ = socket.Emit(CooperateOnAccount, account, auth)
				} else {
					_ = socket.Emit(CooperateOnAccount, nil, auth)
				}
			}
		} else {
			_ = next(nil)
		}

	})
	return cooperateManager
}
